﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Taskbar;
using Microsoft.WindowsAPICodePack.Shell;
using System.Collections;
using System.Diagnostics;
using System.Security;
using System.Media;
using System.Windows.Shell;
using System.Reflection;

namespace GoogleAppsTools
{
    public partial class GoogleManager : Form
    {
        private Process openMailInBrowser = new Process() { StartInfo = new ProcessStartInfo("https://mail.google.com/mail/?tab=cm#inbox") }; //process to open the inbox in a browser
        private Process OpenCalendarInBrowser = new Process() { StartInfo = new ProcessStartInfo("https://www.google.com/calendar/") }; //process to open the calendar in a browser
        private Process composeMail = new Process() { StartInfo = new ProcessStartInfo("https://mail.google.com/mail/?tab=cm#compose") }; //process to compose a new email
        private Process OpenContacts = new Process() { StartInfo = new ProcessStartInfo("https://mail.google.com/mail/?tab=cm#contacts") }; //process to open the contacts list in a browser
        private NewEvent newEventForm = new NewEvent(); //the window to create a new event in the calendar
        private SettingsForm applicationSettingsForm = new SettingsForm(); //the window to change the application settings
        private List<GenericEvent> todaysEvents; //contains todays events
        private List<NewMail> newEmails; //contains the new unread emails
        private SoundPlayer newMailSound = new SoundPlayer(@"c:\Windows\Media\chimes.wav"); //sound to play if there is new mail
        private int numberOfNewEmails; //contains the number of new emails. Used to ensure that the new email chime is not played every tick of the timer
        private TaskbarManager windowsTaskbar = TaskbarManager.Instance; //the taskbarManager object, that manages windows 7 icons, jumplists and thumbnails
        private Microsoft.WindowsAPICodePack.Taskbar.JumpList myJumpList;

        /// <summary>
        /// This method is used to start the program minimised, call createThumbails and show the settingsForm if the username/password strings are empty.
        /// </summary>
        public GoogleManager()
        {
            InitializeComponent();
            this.WindowState = FormWindowState.Minimized; //start the browser windows with calender in minimised
            createThumbnailButtons(); //create the thumbnail buttons
            checkForBlankUsernamePassword(); //check that a username and password has been entered. If blank, the settings window is shown
            WebRefresher.Interval = Properties.Settings.Default.CalendarRefreshRate * 1000; //set the refresh interval of the web browswer
            GetNewEventsTimer.Interval = Properties.Settings.Default.GetNewEventsTime * 1000; //set the timer interval for getting new events
            CheckNewMailTimer.Interval = Properties.Settings.Default.CheckNewMailTime * 1000; //set the timer internal for checking for new mail
            
            //start the timers
            WebRefresher.Start();
            GetNewEventsTimer.Start();
            CheckNewMailTimer.Start();
        }

        /// <summary>
        /// Checks Properties.Settings for entries in username and password. If blank, then the settings form is shown. The settings button also sets the refresh interval.
        /// </summary>
        private void checkForBlankUsernamePassword()
        {
            if (Properties.Settings.Default.username == "" || Properties.Settings.Default.password == "")
            {
                applicationSettingsForm.ShowDialog();
            }
        }

        /// <summary>
        /// Used to create the taskbar thumnails.
        /// </summary>
        private void createThumbnailButtons()
        {
            ThumbnailToolBarButton acknowledgeButton = new ThumbnailToolBarButton(GoogleCalendarApp.green_tick, "Acknowledge today's events");
            acknowledgeButton.Click += delegate
            {
                Properties.Settings.Default.dateAcknowledgedEvents = DateTime.Now.ToShortDateString();
                Properties.Settings.Default.Save();
                setOverlayIcons(todaysEvents.Count, checkForNewMail()); //check for new mail/events today and add the icon overlays accordingly
            };

            ThumbnailToolBarButton OpenMailInBrowserButton = new ThumbnailToolBarButton(GoogleCalendarApp.open_inbox, "Go to inbox");
            OpenMailInBrowserButton.Click += delegate
            {
                openMailInBrowser.Start();
            };

            ThumbnailToolBarButton OpenCalendarInBrowserButton = new ThumbnailToolBarButton(GoogleCalendarApp.open_calendar, "Open calendar in browser");
            OpenCalendarInBrowserButton.Click += delegate
            {
                OpenCalendarInBrowser.Start();
            };

            ThumbnailToolBarButton NewEvent = new ThumbnailToolBarButton(GoogleCalendarApp.new_event, "Create new event");
            NewEvent.Click += delegate
            {
                newEventForm.ShowDialog();
            };

            ThumbnailToolBarButton ComposeMailButton = new ThumbnailToolBarButton(GoogleCalendarApp.compose_mail, "Compose mail");
            ComposeMailButton.Click += delegate
            {
                composeMail.Start();
            };

            ThumbnailToolBarButton OpenContactsButton = new ThumbnailToolBarButton(GoogleCalendarApp.open_contacts, "Open address book");
            OpenContactsButton.Click += delegate
            {
                OpenContacts.Start();
            };

            ThumbnailToolBarButton OpenSettingsForm = new ThumbnailToolBarButton(GoogleCalendarApp.settings2, "Change settings");
            OpenSettingsForm.Click += delegate
            {
                applicationSettingsForm.ShowDialog();
                WebRefresher.Interval = Properties.Settings.Default.CalendarRefreshRate * 1000;
            };

            TaskbarManager.Instance.ThumbnailToolBars.AddButtons(this.Handle, acknowledgeButton, ComposeMailButton, NewEvent, OpenMailInBrowserButton, OpenCalendarInBrowserButton, OpenContactsButton, OpenSettingsForm);
        }

        /// <summary>
        /// This method is used to ensure only 1 instance of the application is running.
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == NativeMethods.WM_SHOWME)
            {
                ShowMe();
            }
            base.WndProc(ref m);
        }

        /// <summary>
        /// This method is used to ensure only 1 instance of the application is running.
        /// </summary>
        private void ShowMe()
        {
            if (WindowState == FormWindowState.Minimized)
            {
                WindowState = FormWindowState.Normal;
            }
            // get our current "TopMost" value (ours will always be false though)
            bool top = TopMost;
            // make our form jump to the top of everything
            TopMost = true;
            // set it back to whatever it was
            TopMost = top;
        }

        /// <summary>
        /// Called after the GoogleCalendar form has finished loading and sets the icon overlay if there is unseen events.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GoogleCalendar_Shown(object sender, EventArgs e)
        {
            setOverlayIcons(findTodaysEvents(), checkForNewMail()); //check for new mail/events today and add the icon overlays accordingly
            AddItemsToJumpList(newEmails, todaysEvents); //populate the jumplist with emails and events
        }

        /// <summary>
        /// Adds new emails and events to of the jumplist.
        /// See http://channel9.msdn.com/coding4fun/articles/Windows-7-Jump-Lists
        /// </summary>
        /// <param name="newEmails"></param>
        private void AddItemsToJumpList(List<NewMail> newEmails, List<GenericEvent> todaysEvents)
        {
            myJumpList = Microsoft.WindowsAPICodePack.Taskbar.JumpList.CreateJumpList(); //create/clear the jumplist

            //add the jumplist items for application functions
            myJumpList.AddUserTasks(new JumpListLink("https://mail.google.com/mail/?shva=1#compose", "Compose new mail")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 214)
            });

            myJumpList.AddUserTasks(new JumpListLink(Assembly.GetEntryAssembly().Location, "Create new event")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 76),
                Arguments = "-2"
            });

            myJumpList.AddUserTasks(new JumpListLink("https://mail.google.com/mail/?tab=cm#inbox", "Go to inbox")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 299)
            });

            myJumpList.AddUserTasks(new JumpListLink(Assembly.GetEntryAssembly().Location, "Got to calendar")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 251)
            });

            myJumpList.AddUserTasks(new JumpListLink("https://mail.google.com/mail/?tab=cm#contacts", "Go to contacts")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 264)
            });

            myJumpList.AddUserTasks(new JumpListLink(Assembly.GetEntryAssembly().Location, "Check for new mail")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 238),
                Arguments = "-3"
            });

            myJumpList.AddUserTasks(new JumpListLink(Assembly.GetEntryAssembly().Location, "Settings")
            {
                IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 207),
                Arguments = "-1"
            });


            //add the jumplist items for new emails
            JumpListCustomCategory newEmailCat = new JumpListCustomCategory("New emails"); //create the custom category 'New emails'
            foreach (NewMail item in newEmails) //for each mail item create a new jump list link
            {
                JumpListLink newMail = new JumpListLink(item.Link, item.Title);
                newMail.IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 156);
                newEmailCat.AddJumpListItems(newMail); //add to the custom category
            }

            //add the jumplists items for todays events
            JumpListCustomCategory todaysEventsCat = new JumpListCustomCategory("Todays events"); //create the custom category 'Todays events'
            foreach (GenericEvent item in todaysEvents) //for each calendar item create a new jump list link
            {
                JumpListLink newEvent = new JumpListLink("https://www.google.com/calendar/render?tab=mc&pli=1", item.Title + ", " + item.StartTime.ToShortTimeString() + "-" + item.EndTime.ToShortTimeString());
                newEvent.IconReference = new IconReference(@"%SystemRoot%\system32\SHELL32.dll", 253); //load the icon
                todaysEventsCat.AddJumpListItems(newEvent); //add to the custom category
            }
            myJumpList.AddCustomCategories(newEmailCat, todaysEventsCat); //when done add the custome category to the jumplist
            myJumpList.Refresh(); //refresh the jumplist
        }

        /// <summary>
        /// This event is called after the GoogleCalendar form has finished loading.  This is where the google server is connected to and todays events are downloaded.  
        /// The try/catch loop is used to catch any errors with server authentication.  If there is an exception, the settingsForm is displayed to reenter username/password.
        /// This method also puts the green plus icon overlay in the taskbar if there are any events today and this has not bee acknowledged today.
        /// </summary>
        private int findTodaysEvents()
        {
            bool stopTrying = false; //property to signal the while loop to stop trying when a connection is successfully made

            while (!stopTrying)
            {
                try
                {
                    SyncService service = new SyncService(); //make a new connection
                    todaysEvents = service.SynchronizeEvents(); //and grab the list of events today
                    stopTrying = true; //download was successful, so stop trying
                }
                catch (Exception ex)
                {
                    System.Windows.Forms.MessageBox.Show(ex.ToString());
                    applicationSettingsForm.ShowDialog();
                }
            }
            return todaysEvents.Count;
        }

        /// <summary>
        /// Checks for new mail. Calls GoogleMailChecker.CheckForNewMail and passes the username/password in Properties.Settings.
        /// Plays a chime if there is new mail.  After the chime is played, it puts the number of new messages in the property numberOfNewEmails.
        /// The next time this method is called (ie after the next interval) if the number of new email messages is the same as last time the chime is not played
        /// This means that the chime will not play over and over again.
        /// </summary>
        private int checkForNewMail()
        {
            SecureString password = (EncryptionClass.DecryptString(Properties.Settings.Default.password)); //the googlemail password
            newEmails = GoogleMailChecker.CheckForNewMail(EncryptionClass.ToInsecureString(EncryptionClass.DecryptString(Properties.Settings.Default.username)), password); //get the new mail and place it in a list

            if (newEmails.Count > 0 && newEmails.Count != numberOfNewEmails) //if there is new mail and this has increased from the last check...
            {
                if (Properties.Settings.Default.NewMailPlaySound)
                    newMailSound.Play(); //play a sound unless sound is turned off
                numberOfNewEmails = newEmails.Count; //and update the last checked property to the current amount.
            }
            return newEmails.Count; //return the number of new emails, to be used when placing the icon overlay
        }

        /// <summary>
        /// Sets the taskbar icon overlay depending on how many unread emails there are and if there are events today that have not been acknowledged.
        /// The icon for unread emails superseeds the icon for unacknowledged events.  If there are more than 9 unread emails, a plus sign is shown instead.
        /// </summary>
        /// <param name="numberOfEmails">Number of unread emails</param>
        private void setOverlayIcons(int numberOfEvents, int numberOfEmails)
        {
            if (numberOfEmails == 0 && numberOfEvents == 0)
                windowsTaskbar.SetOverlayIcon(this.Handle, null, null);
            if (numberOfEmails == 0 && numberOfEvents > 0 && Properties.Settings.Default.dateAcknowledgedEvents == DateTime.Now.ToShortDateString())
                windowsTaskbar.SetOverlayIcon(this.Handle, null, null);
            if (numberOfEmails == 0 && numberOfEvents > 0 && Properties.Settings.Default.dateAcknowledgedEvents != DateTime.Now.ToShortDateString())
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.green_cross, "Events today");
            if (numberOfEmails == 1)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_1_icon, "1 new email");
            if (numberOfEmails == 2)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_2_icon, "2 new emails");
            if (numberOfEmails == 3)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_3_icon, "3 new emails");
            if (numberOfEmails == 4)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_4_icon, "4 new emails");
            if (numberOfEmails == 5)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_5_icon, "5 new emails");
            if (numberOfEmails == 6)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_2_icon, "6 new emails");
            if (numberOfEmails == 7)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_7_icon, "7 new emails");
            if (numberOfEmails == 8)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_2_icon, "8 new emails");
            if (numberOfEmails == 9)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Number_2_icon, "9 new emails");
            if (numberOfEmails > 9)
                windowsTaskbar.SetOverlayIcon(GoogleCalendarApp.Math_plus_icon, numberOfNewEmails.ToString() + " new emails");
        }

        /// <summary>
        /// Event to refresh the GoogleCalendarWebBrowser
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WebRefresher_Tick(object sender, EventArgs e)
        {
            GoogleCalendarWebBrowser.Refresh(); //refresh the calendar web page 
        }

        /// <summary>
        /// Timer event to check new mail
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CheckNewMailTimer_Tick(object sender, EventArgs e)
        {
            setOverlayIcons(todaysEvents.Count, checkForNewMail()); //check for new mail and add the icon overlays accordingly.  A new list of events is not downloaded - the previous list is used instead.
            AddItemsToJumpList(newEmails, todaysEvents); //populate the jumplist with emails and events
        }

        /// <summary>
        /// Timer event to check calendar
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GetNewEventsTimer_Tick(object sender, EventArgs e)
        {
            setOverlayIcons(findTodaysEvents(), checkForNewMail()); //check for new mail/events today and add the icon overlays accordingly
            AddItemsToJumpList(newEmails, todaysEvents); //populate the jumplist with emails and events
        }
    }
}
